using System;
using System.Collections.Generic;
using System.Text;

namespace Adoor.Object.Domain
{
    public class CrossLinkedDomainGroupRemoteSource : IObjectSource
    {
        public CrossLinkedDomainGroupRemoteSource(LinkedDomainCollection linkedDomainCollection)
        {
        }

        private LinkedDomainCollection linkedDomainCollection;

        #region IObjectSource Members

        public IObjectResolver ObjectResolver
        {
            get
            {
                return linkedDomainCollection.ObjectResolver;
            }
            set
            {
                linkedDomainCollection.ObjectResolver = value;
            }
        }

        public void Fill(System.Data.DataSet dataset, Type type)
        {
            linkedDomainCollection[type].RemoteSource.Fill(dataset, type);
        }

        public void Fill(System.Data.DataSet dataset, Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.Fill(dataset, query, args);
        }

        public void Fill(System.Data.DataSet dataset, string query, params object[] args)
        {
            Fill(dataset, linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Fill(System.Data.DataSet dataset, string query, IDictionary<string, object> args)
        {
            Fill(dataset, linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Fill(System.Data.DataSet dataset, string tableName, Type type)
        {
            linkedDomainCollection[type].RemoteSource.Fill(dataset, tableName, type);
        }

        public void Fill(System.Data.DataSet dataset, string tableName, Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.Fill(dataset, tableName, query, args);
        }

        public void Fill(System.Data.DataSet dataset, string tableName, string query, params object[] args)
        {
            Fill(dataset, tableName, linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Fill(System.Data.DataTable table, Type type)
        {
            linkedDomainCollection[type].RemoteSource.Fill(table, type);
        }

        public void Fill(System.Data.DataTable table, Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.Fill(table, query, args);
        }

        public void Fill(System.Data.DataTable table, string query, params object[] args)
        {
            Fill(table, linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Fill(System.Data.DataTable table, string query, IDictionary<string, object> args)
        {
            Fill(table, linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Fill(System.Data.DataTable table, Adoor.Object.Query.ObjectQuery query, IDictionary<string, object> args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.Fill(table, query, args);
        }

        public long GetCount(Type type)
        {
            return linkedDomainCollection[type].RemoteSource.GetCount(type);
        }

        public long GetCount(Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            return group.RemoteSource.GetCount(query, args);
        }

        private static LinkedDomainGroup getCommonLinkedDomain(Adoor.Object.Query.ObjectQuery query)
        {
            Adoor.Object.Query.ObjectPath path = query.Path;
            return getCommonLinkedDomainFromPath(path);
        }

        private static LinkedDomainGroup getCommonLinkedDomainFromPath(Adoor.Object.Query.ObjectPath path)
        {
            LinkedDomainGroup group = null;
            foreach (Adoor.Object.Query.Correlation c in path.Correlations.Values)
            {
                if (c.EntityData != null)
                {
                    //c.EntityData.Domain.
                    if (group == null)
                        group = c.EntityData.Domain.DomainGroup;
                    else
                        throw new NotImplementedException("queries are not yet spported when correlations are in different linked domains");
                }
            }
            return group;
        }

        public long GetCount(string query, params object[] args)
        {
            return GetCount(linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public System.Data.IDataReader GetDataReader(Type type)
        {
            return linkedDomainCollection[type].RemoteSource.GetDataReader(type);
        }

        public System.Data.IDataReader GetDataReader(Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            return group.RemoteSource.GetDataReader(query, args);
        }

        public System.Data.IDataReader GetDataReader(string query, params object[] args)
        {
            return GetDataReader(linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public object GetScalar(Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            return group.RemoteSource.GetScalar(query, args);
        }

        public object GetScalar(string query, params object[] args)
        {
            return GetScalar(linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void Delete(object entity)
        {
            if (entity != null)
            {
                linkedDomainCollection[entity.GetType()].RemoteSource.Delete(entity);
            }
        }

        public void DeleteAll(Type type)
        {
            linkedDomainCollection[type].RemoteSource.DeleteAll(type);
        }

        public void DeleteAll(Adoor.Object.Query.ObjectPath path, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomainFromPath(path);
            group.RemoteSource.DeleteAll(path, args);
        }

        public void DeleteAll(string query, params object[] args)
        {
            DeleteAll(linkedDomainCollection.ObjectResolver.ParsePath(query), args);
        }

        public void ExecuteNonQuery(string query, IDictionary<string, object> args)
        {
            ExecuteNonQuery(linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
            
        }

        public void ExecuteNonQuery(Adoor.Object.Query.ObjectQuery query, IDictionary<string, object> args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.ExecuteNonQuery(query, args);
        }

        public void ExecuteNonQuery(string query, params object[] args)
        {
            ExecuteNonQuery(linkedDomainCollection.ObjectResolver.ParseQuery(query), args);
        }

        public void ExecuteNonQuery(Adoor.Object.Query.ObjectQuery query, params object[] args)
        {
            LinkedDomainGroup group = getCommonLinkedDomain(query);
            group.RemoteSource.ExecuteNonQuery(query, args);
        }

        public event ObjectSourceRetryEventHandler ObjectSourceRetry;

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            
        }

        #endregion
    }
}
